/**
 * 
 */
package org.compiere.acct;

import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level;

import org.compiere.model.MAccount;
import org.compiere.model.MAcctSchema;
import org.compiere.model.MConversionRate;
import org.compiere.model.MCostDetail;
import org.compiere.model.MInvoiceLine;
import org.compiere.model.MLandedCostAllocation;
import org.compiere.model.Mhrmbonus;
import org.compiere.model.MhrmbonusLine;
import org.compiere.model.Mhrmcharge;
import org.compiere.model.Mhrmreserve;
import org.compiere.model.ProductCost;
import org.compiere.model.X_hrm_bonusline_sub;
import org.compiere.model.X_hrm_charge;
import org.compiere.util.DB;
import org.compiere.util.Env;

import extend.org.compiere.hrm.Reserve;

/**
 * @author A.Yerzhanov
 * Apr 25, 2013
 */
public class Doc_hrmbonus extends Doc {
	
	/**
	 *  Constructor
	 * 	@param ass accounting schemata
	 * 	@param rs record
	 * 	@param trxName trx
	 */
	public Doc_hrmbonus(MAcctSchema[] ass, ResultSet rs, String trxName) 
	{
		super(ass, Mhrmbonus.class, rs, null, trxName);
		// Doc_hrmbonus
	}
	
	/** Contained Optional Tax Lines    */
	private DocTax[]        m_taxes = null;

	/**
	 *  Load Specific Document Details
	 *  @return error message or null
	 */	
	protected String loadDocumentDetails() {
		
		Mhrmbonus hr = (Mhrmbonus)getPO();
		setDateDoc(hr.getDateAcct());
		p_lines = loadLines(hr);
		return null;
	} // loadDocumentDetails
	
	private DocLine[] loadLines (Mhrmbonus invoice)
	{
		ArrayList<DocLine> list = new ArrayList<DocLine>();
		DocLine[] dls = new DocLine[list.size()];
		list.toArray(dls);
		
		return dls;
	}


	/**************************************************************************
	 *  Get Source Currency Balance - subtracts line and tax amounts from total - no rounding
	 *  @return positive amount, if total invoice is bigger than lines
	 */
	public BigDecimal getBalance()
	{
		BigDecimal retValue = Env.ZERO;
		return retValue;
	}   //  getBalance


	/**
	 *  Create Facts (the accounting logic) for
	 *  ARI, ARC, ARF, API, APC.
	 *  <pre>
	 *  ARI, ARF
	 *      Receivables     DR
	 *      Charge                  CR
	 *      TaxDue                  CR
	 *      Revenue                 CR
	 *
	 *  ARC
	 *      Receivables             CR
	 *      Charge          DR
	 *      TaxDue          DR
	 *      Revenue         RR
	 *
	 *  API
	 *      Payables                CR
	 *      Charge          DR
	 *      TaxCredit       DR
	 *      Expense         DR
	 *
	 *  APC
	 *      Payables        DR
	 *      Charge                  CR
	 *      TaxCredit               CR
	 *      Expense                 CR
	 *  </pre>
	 *  @param as accounting schema
	 *  @return Fact
	 */
	
	public ArrayList<Fact> createFacts(MAcctSchema as) {
		//
		ArrayList<Fact> facts = new ArrayList<Fact>();
		// 
		
		//MAccount acct = null;
				MAccount acct7210 = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as); //7210
				MAccount acct3120 = getAccount(Doc.ACCTTYPE_HRMIPN, as);	//3120
				MAccount acct3150 = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
				MAccount acct3210 = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
				MAccount acct3220 = getAccount(Doc.ACCTTYPE_HRMOPV, as);	//3220
				MAccount acct3350 = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				MAccount acct3430 = getAccount(Doc.ACCTTYPE_HRMREZERV, as); //3430
				
		Fact fact = new Fact(this, as, Fact.POST_Actual);
		Mhrmbonus bonus = new Mhrmbonus(getCtx(), get_ID(), getTrxName());
		MhrmbonusLine[] lines = bonus.getLinesBonus();
		
		FactLine fl = null;	    		
    	setDateAcct(bonus.getDateFrom());    	
		DocLine DocLine = null;
		X_hrm_bonusline_sub charge = null;
		int C_Charge_ID = 0;
		
		if (!bonus.isSelected()){
			for (int i=0; i < lines.length; i++){
				MhrmbonusLine line = lines[i];
				Integer bp = line.getC_BPartner_ID();
				
				BigDecimal amountCharge = line.gethrm_total();
				BigDecimal amountCNalog = line.gethrm_CNalog();
				BigDecimal amountCOtch = line.gethrm_COtch();
				BigDecimal amountIPN = line.gethrm_IPN();
				BigDecimal amountOPV = line.gethrm_OPV();				
				
				// В начале снимаем ИПН и пенсионные
		    	
				/// IPN
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(null, acct3350, getC_Currency_ID(), amountIPN, null);
							
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMIPN, as);	//3120
				fl = fact.createLine(null, acct3120, getC_Currency_ID(), null, amountIPN);
							
				/// OPV
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(null, acct3350, getC_Currency_ID(), amountOPV, null);
							
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMOPV, as);	//3220
				fl = fact.createLine(null, acct3220, getC_Currency_ID(), null, amountOPV);
				
				// detect c_charge_id and fill hrm_paymentline
				C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_Payment, bonus.getDateFrom());
				charge = MhrmbonusLine.getline(bonus.gethrm_bonus_ID(), bp, C_Charge_ID);
				if (charge == null || charge.get_ID() == 0){
					charge = new X_hrm_bonusline_sub(getCtx(), 0, null);
				}
		    	charge.sethrm_bonus_ID(bonus.gethrm_bonus_ID());
		    	charge.sethrm_bonusLine_ID(line.gethrm_bonusLine_ID());
		    	charge.setC_BPartner_ID(bp);
		    	charge.setC_Charge_ID(C_Charge_ID);
		    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
		    	charge.sethrm_amount(amountCharge);
		    	charge.sethrm_reserve_ID(0);
		    	charge.sethrm_reservesectional_ID(0);
		    	charge.saveEx();
		    	DocLine = new DocLine(charge, this);
		    	
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
				fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), amountCharge, null);
					
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(DocLine, acct3350, getC_Currency_ID(), null, amountCharge);
				
				C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_CNalog, bonus.getDateFrom());				
				charge = MhrmbonusLine.getline(bonus.gethrm_bonus_ID(), bp, C_Charge_ID);
				if (charge == null || charge.get_ID() == 0){
					charge = new X_hrm_bonusline_sub(getCtx(), 0, null);
				}
		    	charge.sethrm_bonus_ID(bonus.gethrm_bonus_ID());
		    	charge.sethrm_bonusLine_ID(line.gethrm_bonusLine_ID());
		    	charge.setC_BPartner_ID(bp);
		    	charge.setC_Charge_ID(C_Charge_ID);
		    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
		    	charge.sethrm_amount(amountCNalog);
		    	charge.sethrm_reserve_ID(0);
		    	charge.sethrm_reservesectional_ID(0);
		    	charge.saveEx();
		    	DocLine = new DocLine(charge, this);
				
				/// CNALOG
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
				fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), amountCNalog, null);
					
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
				fl = fact.createLine(DocLine, acct3150, getC_Currency_ID(), null, amountCNalog);
				
				C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_COtche, bonus.getDateFrom());
				charge = MhrmbonusLine.getline(bonus.gethrm_bonus_ID(), bp, C_Charge_ID);
				if (charge == null || charge.get_ID() == 0){
					charge = new X_hrm_bonusline_sub(getCtx(), 0, null);
				}
		    	charge.sethrm_bonus_ID(bonus.gethrm_bonus_ID());
		    	charge.sethrm_bonusLine_ID(line.gethrm_bonusLine_ID());
		    	charge.setC_BPartner_ID(bp);
		    	charge.setC_Charge_ID(C_Charge_ID);
		    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
		    	charge.sethrm_amount(amountCOtch);
		    	charge.sethrm_reserve_ID(0);
		    	charge.sethrm_reservesectional_ID(0);
		    	charge.saveEx();
		    	DocLine = new DocLine(charge, this);
		    	
				/// COTCH
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
				fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), amountCOtch, null);
					
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
				fl = fact.createLine(DocLine, acct3210, getC_Currency_ID(), null, amountCOtch);
				
			}
			
		}else{
			
			for (int i=0; i < lines.length; i++){
				
				MhrmbonusLine line = lines[i];
				Integer bp = line.getC_BPartner_ID();
				
				BigDecimal amountCharge = line.gethrm_total();
				BigDecimal amountCNalog = line.gethrm_CNalog();
				BigDecimal amountCOtch = line.gethrm_COtch();
				BigDecimal amountIPN = line.gethrm_IPN();
				BigDecimal amountOPV = line.gethrm_OPV();
				
				Reserve reserve = new Reserve(bp, bonus.getDateFrom(), Mhrmreserve.RESERVE_BONUS, acct3430.getAccount_ID());
				BigDecimal reserveCharge = reserve.getSectional(Mhrmreserve.RESERVE_SECTIONAL_CHARGE);
				BigDecimal reserveCNalog = reserve.getSectional(Mhrmreserve.RESERVE_SECTIONAL_CNALOG);
				BigDecimal reserveCOtch = reserve.getSectional(Mhrmreserve.RESERVE_SECTIONAL_COTCH);
				
				
				BigDecimal diff = new BigDecimal(0);
				setDateAcct(bonus.getDateFrom());
				boolean isNew = true;
				
				// 1. Начисления
				
				diff = reserveCharge.add(amountCharge.negate());
				
				if (diff.signum() == -1) { // Если не хвтает на резерве, то занимаем у организации
					
					if (reserveCharge.compareTo(new BigDecimal(0)) == 1) { 
						
						setC_BPartner_ID(bp);
		    	   		//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
		    	   		fl = fact.createLine(null, acct3430, getC_Currency_ID(), reserveCharge, null);
		    	   		fl.setLine_ID(bonus.getBonusLine(Mhrmreserve.RESERVE_SECTIONAL_CHARGE, line.gethrm_bonus_ID(), line.gethrm_bonusLine_ID(), isNew).gethrm_bonusline_sub_ID());
		
		    	   		setC_BPartner_ID(bp);
		    	   		//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
		    	   		fl = fact.createLine(null, acct3350, getC_Currency_ID(), null, reserveCharge);
					}
					
					// detect c_charge_id and fill hrm_paymentline
					C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_Payment, bonus.getDateFrom());
					charge = MhrmbonusLine.getline(bonus.gethrm_bonus_ID(), bp, C_Charge_ID);
					if (charge == null || charge.get_ID() == 0){
						charge = new X_hrm_bonusline_sub(getCtx(), 0, null);
					}
			    	charge.sethrm_bonus_ID(bonus.gethrm_bonus_ID());
			    	charge.sethrm_bonusLine_ID(line.gethrm_bonusLine_ID());
			    	charge.setC_BPartner_ID(bp);
			    	charge.setC_Charge_ID(C_Charge_ID);
			    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
			    	charge.sethrm_amount(diff.negate());
			    	charge.sethrm_reserve_ID(0);
			    	charge.sethrm_reservesectional_ID(0);
			    	charge.saveEx();
			    	DocLine = new DocLine(charge, this);
			    	
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
					fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), diff.negate(), null);
						
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
					fl = fact.createLine(DocLine, acct3350, getC_Currency_ID(), null, diff.negate());
					
				}else{ // Списываем полную сумму
					
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
					fl = fact.createLine(null, acct3430, getC_Currency_ID(), amountCharge, null);
					fl.setLine_ID(bonus.getBonusLine(Mhrmreserve.RESERVE_SECTIONAL_CHARGE, line.gethrm_bonus_ID(), line.gethrm_bonusLine_ID(), isNew).gethrm_bonusline_sub_ID());
		
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
					fl = fact.createLine(null, acct3350, getC_Currency_ID(), null, amountCharge);
					
				}
				
				// В начале снимаем ИПН и пенсионные
		    	
				/// IPN
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(null, acct3350, getC_Currency_ID(), amountIPN, null);
							
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMIPN, as);	//3120
				fl = fact.createLine(null, acct3120, getC_Currency_ID(), null, amountIPN);
							
				/// OPV
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(null, acct3350, getC_Currency_ID(), amountOPV, null);
							
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMOPV, as);	//3220
				fl = fact.createLine(null, acct3220, getC_Currency_ID(), null, amountOPV);
				
				isNew = false;
				
				// 2. Соц. налог  
		    	diff = reserveCNalog.add(amountCNalog.negate());
		    	
		    	if (diff.signum() == -1) { // Если не хвтает на резерве, то занимаем у организации
		    		
		    		if (reserveCNalog.compareTo(new BigDecimal(0)) == 1) {
		    			
		    			setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
						fl = fact.createLine(null, acct3430, getC_Currency_ID(), reserveCNalog, null);
						fl.setLine_ID(bonus.getBonusLine(Mhrmreserve.RESERVE_SECTIONAL_CNALOG, line.gethrm_bonus_ID(), line.gethrm_bonusLine_ID(), isNew).gethrm_bonusline_sub_ID());
		
						setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
						fl = fact.createLine(null, acct3150, getC_Currency_ID(), null, reserveCNalog);
		    		}
		    		
		    		// detect c_charge_id and fill hrm_paymentline
					C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_CNalog,bonus.getDateFrom());
					charge = MhrmbonusLine.getline(bonus.gethrm_bonus_ID(), bp, C_Charge_ID);
					if (charge == null || charge.get_ID() == 0){
						charge = new X_hrm_bonusline_sub(getCtx(), 0, null);
					}
			    	charge.sethrm_bonus_ID(bonus.gethrm_bonus_ID());
			    	charge.sethrm_bonusLine_ID(line.gethrm_bonusLine_ID());
			    	charge.setC_BPartner_ID(bp);
			    	charge.setC_Charge_ID(C_Charge_ID);
			    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
			    	charge.sethrm_amount(diff.negate());
			    	charge.sethrm_reserve_ID(0);
			    	charge.sethrm_reservesectional_ID(0);
			    	charge.saveEx();
			    	DocLine = new DocLine(charge, this);
			    	
		    		setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
					fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), diff.negate(), null);
						
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
					fl = fact.createLine(DocLine, acct3150, getC_Currency_ID(), null, diff.negate());
					
		    	}else{ // Списываем полную сумму
		    		
		    		setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
					fl = fact.createLine(null, acct3430, getC_Currency_ID(), amountCNalog, null);
					fl.setLine_ID(bonus.getBonusLine(Mhrmreserve.RESERVE_SECTIONAL_CNALOG, line.gethrm_bonus_ID(), line.gethrm_bonusLine_ID(), isNew).gethrm_bonusline_sub_ID());
		
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
					fl = fact.createLine(null, acct3150, getC_Currency_ID(), null, amountCNalog);
		    		
		    	}
				
		    	isNew = false;
		    	
		    	// 3. Соц. отчисление		    	
		    	diff = reserveCOtch.add(amountCOtch.negate());
		    	
		    	if (diff.signum() == -1) { // Если не хвтает на резерве, то занимаем у организации
		    		
		    		if (reserveCOtch.compareTo(new BigDecimal(0)) == 1) { 
			    		setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
						fl = fact.createLine(null, acct3430, getC_Currency_ID(), reserveCOtch, null);
						fl.setLine_ID(bonus.getBonusLine(Mhrmreserve.RESERVE_SECTIONAL_COTCH, line.gethrm_bonus_ID(), line.gethrm_bonusLine_ID(), isNew).gethrm_bonusline_sub_ID());
		
						setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
						fl = fact.createLine(null, acct3210, getC_Currency_ID(), null, reserveCOtch);
		    		}
		    		
		    		// detect c_charge_id and fill hrm_paymentline
					C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_COtche, bonus.getDateFrom());
					charge = MhrmbonusLine.getline(bonus.gethrm_bonus_ID(), bp, C_Charge_ID);
					if (charge == null || charge.get_ID() == 0){
						charge = new X_hrm_bonusline_sub(getCtx(), 0, null);
					}
			    	charge.sethrm_bonus_ID(bonus.gethrm_bonus_ID());
			    	charge.sethrm_bonusLine_ID(line.gethrm_bonusLine_ID());
			    	charge.setC_BPartner_ID(bp);
			    	charge.setC_Charge_ID(C_Charge_ID);
			    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
			    	charge.sethrm_amount(diff.negate());
			    	charge.sethrm_reserve_ID(0);
			    	charge.sethrm_reservesectional_ID(0);
			    	charge.saveEx();
			    	DocLine = new DocLine(charge, this);
			    	
		    		setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
					fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), diff.negate(), null);
						
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
					fl = fact.createLine(DocLine, acct3210, getC_Currency_ID(), null, diff.negate());
					
		    	}else{ // Списываем полную сумму
		    		
		    		setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
					fl = fact.createLine(null, acct3430, getC_Currency_ID(), amountCOtch, null);
					fl.setLine_ID(bonus.getBonusLine(Mhrmreserve.RESERVE_SECTIONAL_COTCH, line.gethrm_bonus_ID(), line.gethrm_bonusLine_ID(), isNew).gethrm_bonusline_sub_ID());
		
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
					fl = fact.createLine(null, acct3210, getC_Currency_ID(), null, amountCOtch);
					
		    	}
			} // end for
		}		
		
		facts.add(fact);
		return facts;
		
	} //  createFact
	
	public int checkValidCombination(int account_ID, int C_BPartner_ID){
		
		String sql = " select c_validcombination_id from c_validcombination where account_id = " + account_ID + " and c_bpartner_id = " + C_BPartner_ID;
		
		int AccountValid = 0;
		
		PreparedStatement pstmt = null;
		ResultSet rs = null;

		try{
			pstmt = DB.prepareStatement(sql, null);
			rs = pstmt.executeQuery();
			while (rs.next()) {
				AccountValid = rs.getInt(1);
			}
		}catch(SQLException e){
			log.log(Level.WARNING, e.getLocalizedMessage());
		}
		
		return AccountValid;
		
	}
	
	/**
	 * 	Create Fact Cash Based (i.e. only revenue/expense)
	 *	@param as accounting schema
	 *	@param fact fact to add lines to
	 *	@param multiplier source amount multiplier
	 *	@return accounted amount
	 */
	public BigDecimal createFactCash (MAcctSchema as, Fact fact, BigDecimal multiplier)
	{
		boolean creditMemo = getDocumentType().equals(DOCTYPE_ARCredit)
			|| getDocumentType().equals(DOCTYPE_APCredit);
		boolean payables = getDocumentType().equals(DOCTYPE_APInvoice)
			|| getDocumentType().equals(DOCTYPE_APCredit);
		BigDecimal acctAmt = Env.ZERO;
		FactLine fl = null;
		//	Revenue/Cost
		for (int i = 0; i < p_lines.length; i++)
		{
			DocLine line = p_lines[i];
			boolean landedCost = false;
			if  (payables)
				landedCost = landedCost(as, fact, line, false);
			if (landedCost && as.isExplicitCostAdjustment())
			{
				fact.createLine (line, line.getAccount(ProductCost.ACCTTYPE_P_Expense, as),
					getC_Currency_ID(), null, line.getAmtSource());
				//
				fl = fact.createLine (line, line.getAccount(ProductCost.ACCTTYPE_P_Expense, as),
					getC_Currency_ID(), line.getAmtSource(), null);
				String desc = line.getDescription();
				if (desc == null)
					desc = "100%";
				else
					desc += " 100%";
				fl.setDescription(desc);
			}
			if (!landedCost)
			{
				MAccount acct = line.getAccount(
					payables ? ProductCost.ACCTTYPE_P_Expense : ProductCost.ACCTTYPE_P_Revenue, as);
				if (payables)
				{
					//	if Fixed Asset
					if (line.isItem())
						acct = line.getAccount (ProductCost.ACCTTYPE_P_InventoryClearing, as);
				}
				BigDecimal amt = line.getAmtSource().multiply(multiplier);
				BigDecimal amt2 = null;
				if (creditMemo)
				{
					amt2 = amt;
					amt = null;
				}
				if (payables)	//	Vendor = DR
					fl = fact.createLine (line, acct,
						getC_Currency_ID(), amt, amt2);
				else			//	Customer = CR
					fl = fact.createLine (line, acct,
						getC_Currency_ID(), amt2, amt);
				if (fl != null)
					acctAmt = acctAmt.add(fl.getAcctBalance());
			}
		}
		//  Tax
		for (int i = 0; i < m_taxes.length; i++)
		{
			BigDecimal amt = m_taxes[i].getAmount();
			BigDecimal amt2 = null;
			if (creditMemo)
			{
				amt2 = amt;
				amt = null;
			}
			FactLine tl = null;
			if (payables)
				tl = fact.createLine (null, m_taxes[i].getAccount(m_taxes[i].getAPTaxType(), as),
					getC_Currency_ID(), amt, amt2);
			else
				tl = fact.createLine (null, m_taxes[i].getAccount(DocTax.ACCTTYPE_TaxDue, as),
					getC_Currency_ID(), amt2, amt);
			if (tl != null)
				tl.setC_Tax_ID(m_taxes[i].getC_Tax_ID());
		}
		//  Set Locations
		FactLine[] fLines = fact.getLines();
		for (int i = 0; i < fLines.length; i++)
		{
			if (fLines[i] != null)
			{
				if (payables)
				{
					fLines[i].setLocationFromBPartner(getC_BPartner_Location_ID(), true);  //  from Loc
					fLines[i].setLocationFromOrg(fLines[i].getAD_Org_ID(), false);    //  to Loc
				}
				else
				{
					fLines[i].setLocationFromOrg(fLines[i].getAD_Org_ID(), true);    //  from Loc
					fLines[i].setLocationFromBPartner(getC_BPartner_Location_ID(), false);  //  to Loc
				}
			}
		}
		return acctAmt;
	}	//	createFactCash
	
	
	/**
	 * 	Create Landed Cost accounting & Cost lines
	 *	@param as accounting schema
	 *	@param fact fact
	 *	@param line document line
	 *	@param dr DR entry (normal api)
	 *	@return true if landed costs were created
	 */
	private boolean landedCost (MAcctSchema as, Fact fact, DocLine line, boolean dr) 
	{
		int C_InvoiceLine_ID = line.get_ID();
		MLandedCostAllocation[] lcas = MLandedCostAllocation.getOfInvoiceLine(
			getCtx(), C_InvoiceLine_ID, getTrxName());
		if (lcas.length == 0)
			return false;
		
		//	Calculate Total Base
		double totalBase = 0;
		for (int i = 0; i < lcas.length; i++)
			totalBase += lcas[i].getBase().doubleValue();
		
		//	Create New
		MInvoiceLine il = new MInvoiceLine (getCtx(), C_InvoiceLine_ID, getTrxName());
		for (int i = 0; i < lcas.length; i++)
		{
			MLandedCostAllocation lca = lcas[i];
			if (lca.getBase().signum() == 0)
				continue;
			double percent = lca.getBase().doubleValue() / totalBase;
			String desc = il.getDescription();
			if (desc == null)
				desc = percent + "%";
			else
				desc += " - " + percent + "%";
			if (line.getDescription() != null)
				desc += " - " + line.getDescription(); 
			
			//	Accounting
			ProductCost pc = new ProductCost (Env.getCtx(), 
				lca.getM_Product_ID(), lca.getM_AttributeSetInstance_ID(), getTrxName());
			BigDecimal drAmt = null;
			BigDecimal crAmt = null;
			if (dr)
				drAmt = lca.getAmt();
			else
				crAmt = lca.getAmt();
			FactLine fl = fact.createLine (line, pc.getAccount(ProductCost.ACCTTYPE_P_CostAdjustment, as),
				getC_Currency_ID(), drAmt, crAmt);
			fl.setDescription(desc);
			fl.setM_Product_ID(lca.getM_Product_ID());
			
			//	Cost Detail - Convert to AcctCurrency
			BigDecimal allocationAmt =  lca.getAmt();
			if (getC_Currency_ID() != as.getC_Currency_ID())
				allocationAmt = MConversionRate.convert(getCtx(), allocationAmt, 
					getC_Currency_ID(), as.getC_Currency_ID(),
					getDateAcct(), getC_ConversionType_ID(), 
					getAD_Client_ID(), getAD_Org_ID());
			if (allocationAmt.scale() > as.getCostingPrecision())
				allocationAmt = allocationAmt.setScale(as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP);
			if (!dr)
				allocationAmt = allocationAmt.negate();
			// AZ Goodwill
			// use createInvoice to create/update non Material Cost Detail
			MCostDetail.createInvoice(as, lca.getAD_Org_ID(), 
					lca.getM_Product_ID(), lca.getM_AttributeSetInstance_ID(),
					C_InvoiceLine_ID, lca.getM_CostElement_ID(),
					allocationAmt, lca.getQty(),
					desc, getTrxName());
			// end AZ
		}
		
		log.config("Created #" + lcas.length);
		return true;
	}	//	landedCosts
	
	@Override
	public int getC_Currency_ID() {
		int result = super.getC_Currency_ID();
		if (result <= 0) {
			int AD_Client_ID =  Env.getAD_Client_ID(getCtx());
		    MAcctSchema[] acctSchema = MAcctSchema.getClientAcctSchema(getCtx(), AD_Client_ID, getTrxName());
		    for(MAcctSchema as: acctSchema) {
		    	if (as.isActive()) { //TODO определить актуальную схему по клиенту!
		    		result = as.getC_Currency_ID();
		    	}
		    }
		}
		return result;
	}
}  //  Doc_HRMBONUS
